************************* * SNES translucency FAQ * * by Bregalad * ************************* Original: April 18th, 2009 New revision: May 21st, 2015 ------------ Introduction ------------ The translucency on the SNES, while documented properly by multiple other people, always gave me some headaches understanding how it works. Now that I've figured the truth (I guess), I'm writing a small document to spare someone else the headaches I've had if if could be useful to someone wanting to do a homebrew program for the SNES or to just understand how their favourite games works internally. IMPORTANT NOTE : I can't guarantee the technical accuracy of anything mentioned in this document. I tried to make it as accurate as I could, but for accurate reference, please check Anomie's documents. This document is for explaining translucency both on the technical side and the practical side, with a bias towards the later. ANOTHER IMPORTANT NOTE : The word "transparency" is sometimes used for "translucency". I chose to use always "translucent", in order to not confuse with the transparency that is using palette entry #0 in tiles. Another word is "colour math", for reasons that will soon be obvious. First of all, the SNES hardware does not support any kind of "real" translucency. It just have a way to simulate it, but this way is limited. On the other hand, the SNES can do cool effect real translucency cannot, like image inversion. ------------------------------------ Translucency effects the SNES can do ------------------------------------ The SNES supports 4 kind of translucent-like effects: - Colour addition: Useful for drawing translucent rays of light or to just lighten some layers. Example : Chrono Trigger uses it in Crono's room when you open the curtain at the start of the game. - Colour averaging (addition then halving): This is the most widely used translucency effect. It can average colours of two planes, giving the user one of them is translucent (which one exactly is entirely psychological). This allow to draw translucent water, translucent fog/clouds, translucent shadows, ghost sprites, etc... Example : The water in Secret of Mana. - Colour subtraction: Useful for translucent shadows, simulating night or stormy weather, etc... Example : "Torchlight Trouble" level in Donkey Kong Country - Colour subtraction then halving: This one is the least useful effect, and noes not make any sense in terms of translucency. I've never found any game that uses this yet, thus I cannot give an example. I believe it could be used for anything that is supposed to be very dark, yet "slightly translucent", for example the background of a text box. ------------------------------------------- Hardware limitation of translucency effects ------------------------------------------- In addition to this there is a primordial limitation : The colour addition/subtraction always happen between 2 pixels of given BG plane or sprites. At most two different layers are implied in translucency. For example, imagine a game with a translucent ghost sprite that stand on a solid brick background, and have a translucent fog covering all that. While both translucency effects are possible separately, the SNES hardware can just not do what is described. Either the background, the fog or the ghost will be "clipped" depending how it is set up. There can be as many translucent objects/layers as you'd like on the screen, but they can never overlap. A second limitation is that a sprite can never be translucent through another sprite, because all sprites are merged into a single plane in the viewpoint of the SNES PPU. A background layer should be used to simulate a sprite, should this effect be desired. A good example are the saving points in Final Fantasy V. It would make sense to have them being sprites, but because they need to be translucent on the main character sprite, they are indeed background. -------------------------- Main screen and sub screen -------------------------- The concept of main screen and sub screen will not be introduced. The SNES have 4 background layers, one sprite layer (which is a pseudo-plane constituted by all sprites). The SNES can enable each of those 5 layers separately and this results in two combined planes. Those two planes are called the main screen and the sub screen. Unfortunately there is 2 numberings of SNES background: They can be numbered 1-4 (ZSNES) or 0-3 (Snes9x). Recent Snes9x switched to 1-4, thus I'll use 1-4. To convert to 0-3 subtract one. To determine which pixel is rendered to the main screen and sub-screen, the SNES do an algorithm close to the following twice for every pixel: Once for main screen and once for sub-screen (it may not be accurate, but it should be pretty close to the truth): - Only if sprites are enabled and not disabled by window clipping : * Of all sprites grab the first 32 on the current scanline (after having converted everything in up to 34 8x8 sprites, dropping the rest) * Determine the first sprite among those 32 which have a non-transparent pixel at this exact position. The first sprite is picked, even if another sprite had higher priority. * Remember the priority number of that sprite (0 to 3) - Get the corresponding pixel for all enabled BGs. We skip when the pixel is transparent (colour #0), when the BG is disabled, when the BG does not exist in the graphic mode (0-7) that is in use, and when it is disabled by window clipping. - Apply the BG and sprite order that is dependant on the graphic mode. This order is widely documented already and I don't want to enter into details here (check Anomie's doc if you want to go more into details). When all enabled and non-clipped layers result in transparent pixels, the background colour (palette's entry #0) is used for the main screen. For the sub screen the constant colour set by the register $2132 is used. It is now possible to build what the main screen and the sub screen looks like. -------------------- Apply colour effects -------------------- By default (when no translucency is used), the main screen is what is shown on the screen. Translucency can be enabled individually for all layers and for the colour-0 background. When translucency is enabled eight effects are available: 1) One of the four math effects mentioned above (add, average, subtract, subtract then half) is done with the constant colour stored in register $2132. This is useful to simulate night or fog without wasting a BG layer for this sloe purpose. Combined with window clipping, nice shapes can be done that way, such as the numbers in Super Mario Kart. 2) One of the four math effects mentioned above is applied with the corresponding sub screen pixel, and if that sub screen pixel is translucent do as in 1). This is useful if you want any layer to actually be translucent. The effect can be enabled separately for all layers of the main screen, with the exception of sprites. For sprites, the effect is either always disabled, or if enabled only sprites using palettes 4-7 have the effect applied to them. Sprites with palettes 0-3 are still part of the main screen, but no translucent effect can be applied to them. It is possible to make palettes 4-7 mirror exactly 0-3 so to be able to select translucency individually on each sprite, but in most cases another work around is done. The exact operation is the following: - Colour adding : R, G and B are added separately, if the result is greater than 31 it is forced to be 31 (so it can't "overflow"). In this mode the "neutral" colour is black, any layer added with black won't be affected. It is possible that a layer adds up with itself so that it becomes twice as bright. Since addition is commutative, having layer A in main screen added with layer B in sub screen has the same effect than making it the other way around (exception seen below). - Colour adding + halving (averaging): R, G and B are added separately, and the 6-bit result is shifted right once. There is no neural colour, but it is possible for a layer to be averaged with itself so that it appears unaffected by translucency when technically it is translucent. Again since the addition is commutative, you can get the same effect by 2 different ways. - Colour subtracting: The sub screen is subtracted from the main screen. If the result is smaller than 0, it is forced to 0. The neutral colour is black (any colour subtracted by black isn't modified). It is possible for a layer to be subtracted from itself so that it becomes constant black. - Colour subtracting + halving: Similar to above, but the result is shifted to the right. Almost always results in ridiculously dark colours. IMPORTANT NOTE : When either screen pixel is translucent (all layers that are enabled and that exists are translucent or are clipped), the result of the addition/subtraction is never halved. - If the main screen is translucent, colour #0 is added/subtracted with sub screen pixel if enabled, never halved. - If the sub screen is translucent, the colour constant set in $2132 is either added or subtracted from the main screen, never halved. ----------------- Concrete examples ----------------- Now let's move to actual concrete cases. Notice: Unless specified, the BG colour (palette entry #0) and constant colour $2132 are both set to black. ---- Example 1 ---- Let's admit that translucent ghosts sprites are wanted against a solid background on BG1. The following set-up does the thing: * Setup 1 * Main screen : Sprites Sub screen : BG1 Translucency enabled on : Sprites, backdrop (add+half sub screen) The sprites are displayed and because translucency is enabled (with addition+half operation), it is averaged with the background layer, resulting in ghost sprites. When no sprite is here the background is shown normally, because added with colour #0 backdrop which is black. But translucency is enabled only for sprites using palette 4-7. Sprites using palette 0-3 will be solid. This is exactly what happens in Super Mario World in ghost's houses : Some sprite items such as 1-up mushrooms becomes accidentally translucent because of their palette. To fix this problem, commutativity of addition is used. By using a translucent BG1 in front of opaque sprites, the ghost will look the exact same: * Setup 2 * Main screen : BG1 Sub screen : Sprites Translucency enabled on : BG1 (add+half sub screen) This time, all sprites are placed on the sub screen, and all of them appear translucent, no matter their palette. This is the only difference between both setups. If there is any transparent pixels in BG1 and there is a sprite at the same location, the sprite will look solid on that pixel (in setup 1) or will not be visible (in setup 2), which is not the desired effect where you'd want it to be averaged with black (the backdrop colour). The simplest is to use a solid non-backdrop black colour instead of relying on backdrop colour to be black, effectively reducing the amount of usable colours for the background from 16 to 15. ------ Example 2 ------ Now a more complex case. A translucent background of fog should be displayed above a game level. The addition is commutative, thus a translucent level on a opaque layer of fog is also an option, the result will be exactly the same. Let's admit that: * The fog is in BG2 * The level is made of BG1 and sprites * There is a status bar on BG3 that should not be translucent. It can be achieved with the following set-up: * Setup 3 * Main screen : BG1, sprites, BG3 Sub screen : BG2 Translucency enabled on : BG1, sprites (add+half sub screen) This will get the desired result, but only sprites using palette 4-7 will appear below the fog. Sprites using palettes 0-3 will appear above the fog (unless they are hidden behind BG1 or BG3). In order to fix the problem, the following setup does the trick: * Setup 4 * Main screen : BG2, BG3 Sub screen : BG1, sprites Translucency enabled on : BG2 (add+half sub screen) That way all the sprites are below the fog and the palette numbers do not matter. Now what if part of the status bar is a sprite (for a weapon icon), and appears to be below the fog? There is an easy way around the problem with the following setup: * Setup 5 * Main screen : BG2, BG3, sprites Sub screen : BG1, sprites Translucency enabled on : BG2 (add+half subscreen) (The priority bit for all tiles in the map that contain the fog should also be set) What now determines which sprites are above the fog and which are below is no longer the palette, but the priority. The weapon icon which stands in the status bar should use priority 3 (above the BG2 so it's not affected by translucency), and the sprites in the level should use priority 2 (hidden below hi-priority BG2, but shows up because of translucency is enabled on that BG2). As sprites are both in a main screen and the sub screen, it makes this possible, while getting rid of the annoying palette number dependencies. Similar concept applies to BGs if you want a portion of them to be translucent and another portion to be opaque using the individual tile priority feature. ----- Example 3 ------ A third concrete case: A level should be shown at night using translucency, but the status bar shall not be darkened. * The level uses BG0 and BG1 * The status bar uses BG2 A simple way is to subtract greyish-brown from BG0, BG1 and sprites, so that dark greyish-blue remains. So set a greyish brown on $2132 (not too light else the screen will become too dark) and have the following set-up: * Setup 6 * Main screen : BG1, BG2, BG3, sprites Sub screen : - Translucency enabled on : BG1, BG2, sprites (subtract colour constant) That would be fine if it didn't suffer from the same flaw as setup 3, whenever the sprites are darkened depends on their palette, which is not practical. The solution to that is to set the sprites in the sub screen. You could do as in setup 5, but it would waste one layer for solid brown: Let's admit both BG1 and BG2 are needed for the level. By changing the palette entry #0 to greyish-brown and try this setup: * Setup 7 * Main screen : BG3 Sub screen : BG1, BG2, BG3, sprites Translucency enabled on : Backdrop (subtract sub screen) The level will appear with negative colours because it is subtracted from the yellow-brown constant. This is exactly what happens in Donkey Kong's country infamous "Torchlight Trouble" level (in "Gorilla Glacier"). They wanted to darken the screen, and that for all sprite numbers, not only 4-7. By disabling translucency in Snes9x by pressing '9', the level is seen negative! The negative colours of the level can be compensated by XORing all palette entries, except the status bar related ones, with $ffff. The same problem as for setup 4 arise again: A weapon sprite icon in the status bar will be darkened, when it wasn't supposed to. That's where clipping windows could come in handy. Or since the palette is manipulated anyway, it could be clever to tune all entries to night colours manually, allowing for translucent ghost in the night. I hope the reader should now know enough to figure this kind of tricks by himself. I hope this document was useful or at least informative, and that pseudo-translucency on the SNES in the form of additions and subtractions of main/sub screens won't ever give you headaches anymore. In order to create a seupt with translucency, what should be determined is what is added/subtracted to/from what, and play a little with layer priorities, and that sprites should always be part of the sub screen if you don't want their palette number to be taken in account. The key is that addition's commutativity, as well as the voidness of operations such averaging a colour with itself, are almost always used in order to get a practical setup for a particular case.